package com.example.readerapp.myandserver.util;

import android.os.Build;

import java.io.*;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.Provider;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.*;

import static java.util.zip.ZipEntry.STORED;

public class ZipUtil
{

    /**
     * 压缩多个文件成一个zip文件
     *
     * @param srcFiles：源文件列表
     * @param destZipFile：压缩后的文件
     */
    public static void toZip(List<File> srcFiles, File destZipFile) {
        byte[] buf = new byte[1024];
        try {
            // ZipOutputStream类：完成文件或文件夹的压缩
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(destZipFile));
            for (int i = 0; i < srcFiles.size(); i++) {
                FileInputStream in = new FileInputStream(srcFiles.get(i));
                // 给列表中的文件单独命名
                out.putNextEntry(new ZipEntry(srcFiles.get(i).getName()));
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                out.closeEntry();
                in.close();
            }
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取zip文件的文本内容
     * @param zipPath zip文件地址 参考值："D:\\JAVA代码\\UtilDEV\\src\\main\\resources\\test.zip"
     * @param fileName 文本文件的名称(带格式如：name.txt、name.html) 参考值：config.txt、1.html
     * */
    synchronized public static String readTextFromZip(String zipPath,String fileName) throws Exception
    {
        if(zipPath==null)
            throw new NullPointerException();
        ZipFile zipFile=new ZipFile(zipPath);
        ZipEntry zipEntry=null;
        String content="";
        File file=new File(zipPath);
        try
        {
            if (file.exists())
            {
                ZipInputStream zipInputStream = null;

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                {
                    zipInputStream = new ZipInputStream(new FileInputStream(zipPath), Charset.forName("GBK"));
                }
                try
                {
                    while ((zipEntry = zipInputStream.getNextEntry()) != null)
                    {
                        if (zipEntry.getName().equals(fileName))
                        {
                            BufferedReader br = new BufferedReader(new InputStreamReader(zipFile.getInputStream(zipEntry)));
                            String line;
                            while ((line = br.readLine()) != null)
                            {
                                content = content + "\n" + line;
                            }
                            br.close();
                            break;
                        }
                    }
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
                finally
                {
                    zipInputStream.closeEntry();
                    zipInputStream.close();
                }

            }
        }catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            zipFile.close();
        }

     //   System.out.println("BEGIN_"+content+"__END");
        return content;
    }
    /**
     * 向zip文件中的文本文件中写入内容，代价十分高昂，为了修改一个文件，必须把其他所有文件进行备份和恢复
     * 参考用法：ZipUtil.writeTextIntoZipFile("D:\\JAVA代码\\UtilDEV\\src\\main\\resources\\test.zip","config.txt","修改",true);
     * @param zipPath 待修改的zip文件的路径
     * @param fileName 待修改的文本文件的名称，需要后缀
     * @param content 写入的内容
     * @param append 是否清空原内容
     * */
   synchronized public static void writeTextIntoZipFile(String zipPath,String fileName,String content,boolean append) throws Exception
    {
        if(zipPath==null)
            throw new NullPointerException();
        File zipFile=new File(zipPath);
        ZipFile zf=new ZipFile(zipFile);
        try{

                //备份zip中的其他文件
                HashMap<String, byte[]> backup = new HashMap<>();
                Enumeration<? extends ZipEntry> backupEntries = zf.entries();
                while (backupEntries.hasMoreElements())
                {
                    ZipEntry entry = backupEntries.nextElement();
                    if (!entry.getName().equals(fileName))
                    {
                        backup.put(entry.getName(), readAllBytes(zf.getInputStream(entry)));
                    }
                }
                //开始修改指定文件
                Enumeration<? extends ZipEntry> entries = zf.entries();
                while (entries.hasMoreElements())
                {
                    ZipEntry entry = entries.nextElement();

                    if (entry.getName().equals(fileName))
                    {
                        ZipOutputStream zos = null;
                        try
                        {

                            //要求在在原文件之后添加内容，不清空原文件
                            if (append)
                            {
                                //读取原内容
                                InputStream inputStream = zf.getInputStream(entry);
                                byte[] r = readAllBytes(inputStream);
                                String o = new String(r, StandardCharsets.UTF_8);
                                content = o + "\n" + content;
                            }
                            //修改内容
                            byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
                            //创建新条目并写入zip文件
                            ZipEntry newEntry = new ZipEntry(entry.getName());
                            newEntry.setMethod(STORED);
                            newEntry.setSize(bytes.length);
                            newEntry.setCompressedSize(bytes.length);

                            CRC32 crc32 = new CRC32();
                            crc32.update(bytes);
                            newEntry.setCrc(crc32.getValue());

                            zos = new ZipOutputStream(new FileOutputStream(zipFile));
                            zos.putNextEntry(newEntry);
                            zos.write(bytes);
                            //写入备份的其他条目
                            for (Map.Entry mapEntry : backup.entrySet())
                            {
                                bytes = (byte[]) mapEntry.getValue();
                                ZipEntry backupEntry = new ZipEntry((String) mapEntry.getKey());
                                backupEntry.setMethod(STORED);
                                backupEntry.setSize(bytes.length);
                                backupEntry.setCompressedSize(bytes.length);

                                CRC32 backupCrc32 = new CRC32();
                                backupCrc32.update(bytes);
                                backupEntry.setCrc(backupCrc32.getValue());
                                zos.putNextEntry(backupEntry);
                                zos.write(bytes);
                            }
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                        finally
                        {
                            zos.closeEntry();
                            zos.close();
                            break;
                        }
                    }
                }



        }catch (Exception e)
        {
            e.printStackTrace();
        }finally
        {
            zf.close();
        }

    }
    public static void writeTextIntoZipFileHighSpeed(String zipPath,String fileName,String content,boolean append) throws Exception
    {
        //System.out.println("请求--ziputil"+content);
        File path2File=new File(zipPath);
        try {
            FileSystem fileSystem = null;//path2File是压缩包的File

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            {
                fileSystem = FileSystems.newFileSystem(path2File.toPath(), null);
            }
            else{
                System.out.println("请求--文件21失败");
            }


            Path textPath = null;  //获取压缩包内文件的path
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            {
                textPath = fileSystem.getPath("\\"+fileName);
            }
            else{
                System.out.println("请求--文件2阿萨1失败");
            }

            BufferedReader bufferedReader= null;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            {
                bufferedReader = Files.newBufferedReader(textPath, StandardCharsets.UTF_8);
            } else{
                System.out.println("请求--文件2ece阿萨1失败");
            }
            String newContent="";
            String line;
            if(append)
                while ((line= bufferedReader.readLine())!=null)
                {
                    if(!line.equals("\n"))
                    newContent=line+"\n";
                }
            newContent=newContent+content;

            bufferedReader.close();
            BufferedWriter bufferedWriter= null;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            {
                bufferedWriter = Files.newBufferedWriter(textPath, StandardCharsets.UTF_8);
            } else{
                System.out.println("请求--wdw文件2阿萨1失败");
            }
            bufferedWriter.write(newContent);
            bufferedWriter.flush();
            bufferedWriter.close();
            fileSystem.close();


    }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
    private static byte[] readAllBytes(InputStream inputStream) throws Exception
    {
        if(inputStream==null)
        {
            System.out.println("输入流为空");
            return null;
        }
        ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
        byte[] buffer=new byte[1024];
        int length;
        while ((length=inputStream.read(buffer))!=-1)
        {
            outputStream.write(buffer,0,length);
        }
        return outputStream.toByteArray();
    }
}


